#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "shmem.h"

#include <sys/wait.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include "msg_queue_peer.h"

union val_t
{ 
    int b_val;  //bool类型存储空间
    int i_val;   //整形值存储空间
    float f_val;  //浮点值存储空间
};

typedef struct data1
{
    int key;
	int set;
	int type;
	union val_t val;
}Data;

struct data2
{
  Data temp;//温度
	Data hum;//湿度
	Data tate;//
	Data time;
	Data fall;
	Data light;
	Data fan;
	Data air;
	Data buzzer;
	Data video;
	Data compass;
	Data step;
} value;


struct std_node
{
    int key;             //唯一键值
    int type;            //数据点类型
    int dev_type;        //数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; //变化上报后需要更新旧值
    union val_t new_val; //从共享内存取出最新数据，放到new_val中
    int ret;             //默认为-1，采集成功后设置为0，采集失败再置-1
};

static struct shm_param para;

#define MAX_NODE 128 // 最大支持设备数目，实际可用是127
#define STD_NODE_LEN sizeof(struct std_node)
#define MAX_NODE_SIZE (MAX_NODE * STD_NODE_LEN)


static int *total;           // 指向共享内存中数据节点总个数
static struct std_node *node_arr; // 指向共享内存中节点缓存数组头

void *stm32_read(void *arg)
{
    int ret = -1;

    ret = shm_init(&para, "SHMEM", MAX_NODE_SIZE);
    if (ret < 0)
    {
        return -1;
    }

    void *node_p = shm_getaddr(&para);
    if (node_p == NULL)
    {
        return -1;
    }

    memset(node_p, 0, MAX_NODE_SIZE);
    total = (int *)node_p;
    // 后面空间存储数据点
    node_arr = (struct std_node *)(node_p + sizeof(int));
    *total = 12;
    int i;

    node_arr[0].key=301;
    node_arr[1].key=302;
    node_arr[2].key=303;
    node_arr[3].key=304;
    node_arr[4].key=305;
    node_arr[5].key=306;
    node_arr[6].key=307;
    node_arr[7].key=308;
    node_arr[8].key=309;
    node_arr[9].key=310;
    node_arr[10].key=311;
    node_arr[11].key=312;

    int rett;
    // struct std_node buf[12] = {0};
    int acceptfd = *((int *)arg);


    i=0;
    // 6.接收、发送消息（recv、send）--》通话
    while (1)
    {
        rett = recv(acceptfd, &value, sizeof(value), 0);
        if (rett < 0)
        {
            perror("recv err");
            return NULL;
        }
        else if (rett == 0)
        {
            printf("client exit\n");
            break;
        }
        else
        {               
           if(value.temp.set==1)
           {
             value.temp.set=0;
             node_arr[0].new_val.f_val=value.temp.val.f_val;
           }
           if(value.hum.set==1)
           {
             value.hum.set=0;
             node_arr[1].new_val.f_val=value.hum.val.f_val;
           }
           if(value.tate.set==1)
           {
             value.tate.set=0;
             node_arr[2].new_val.f_val=value.tate.val.f_val;
           }
           if(value.time.set==1)
           {
             value.time.set=0;
             node_arr[3].new_val.i_val=value.time.val.i_val;
           }
           if(value.fall.set==1)
           {
             value.fall.set=0;
             node_arr[4].new_val.b_val=value.fall.val.b_val;
             printf("value:%d\n",node_arr[4].new_val.b_val);
             value.fall.set=0;
           }
           if(value.light.set==1)
           {
             value.light.set=0;
             node_arr[5].new_val.b_val=value.light.val.b_val;
           }
           if(value.fan.set==1)
           {
             value.fan.set=0;
             node_arr[6].new_val.i_val=value.fan.val.i_val;
           }
           if(value.air.set==1)
           {
             value.air.set=0;
             node_arr[7].new_val.i_val=value.air.val.i_val;
           }
           if(value.buzzer.set==1)
           {
             value.buzzer.set=0;
             node_arr[8].new_val.b_val=value.buzzer.val.b_val;
           }
           if(value.video.set==1)
           {
             value.video.set=0;
             node_arr[9].new_val.b_val=value.video.val.b_val;
           }
           if(value.compass.set==1)
           {
             value.compass.set=0;
             node_arr[10].new_val.i_val=value.compass.val.i_val;
           }
           if(value.step.set==1)
           {
             value.step.set=0;
             node_arr[11].new_val.i_val=value.step.val.i_val;
           }
            
        }
        
        // memset(buf, 0, sizeof(buf));
    }
    // 7.关闭套接字（close）------------------》挂电话
    close(acceptfd);
    pthread_exit(NULL);
    return NULL;
}

void *stm32_write(void *arg)
{
    int ret;
    char buf[128] = {0};
    int acceptfd = *((int *)arg);

    while(1)
    {
        fgets(buf, sizeof(buf), stdin);
        if (buf[strlen(buf) - 1] == '\n')
            buf[strlen(buf) - 1] = '\0';
        if (!strcmp("quit", buf))
            break;
        send(acceptfd, buf, sizeof(buf), 0);
    }
    
    // 7.关闭套接字（close）------------------》挂电话
    close(acceptfd);
    pthread_exit(NULL);
    return NULL;
}

int main(int argc, char const *argv[])
{
    char buf[32] = {0};
    ssize_t ret;
    int acceptfd;
    pthread_t tid,tid2;

    // 1.创建流式套接字（socket）----------》有手机
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        perror("socket err");
        return -1;
    }
    printf("sockfd:%d\n", sockfd);
    // 2.指定网络信息---------------------------》有号码
    struct sockaddr_in saddr, caddr;
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    // saddr.sin_addr.s_addr = inet_addr("0.0.0.0");
    // 自动获取本机IP
    // 0.0.0.0:本机上所有的IPV4的地址
    // INADDR_ANY
    saddr.sin_addr.s_addr = INADDR_ANY;
    int len = sizeof(caddr);
    // 3.绑定套接字（bind）------------------》绑定手机
    if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
    {
        perror("bind err");
        return -1;
    }
    printf("bind ok\n");
    // 4.监听套接字（listen）-----------------》待机
    // 将主动套接字变为被动套接字
    if (listen(sockfd, 6) < 0)
    {
        perror("listen err");
        return -1;
    }
    printf("listen ok\n");
    // 5.接收客户端连接请求（accept）---》接电话
    while (1)
    {
        // 第二个参数:存放客户端信息
        // 第三个参数:结构体大小的地址
        acceptfd = accept(sockfd, (struct sockaddr *)&caddr, &len);
        if (acceptfd < 0)
        {
            perror("accept err");
            return -1;
        }
        printf("accept ok\n");
        printf("port:%d ip:%s\n", ntohs(caddr.sin_port), inet_ntoa(caddr.sin_addr));

        // 每有一个客户端链接,就创建一个线程,用于通信
        pthread_create(&tid, NULL, stm32_read, &acceptfd);
        pthread_create(&tid2, NULL, stm32_write, &acceptfd);
        // 游离态:pthread_detach,当线程结束后自动回收,不可以用pthread_join回收
        // 回收态:需要手动回收线程资源,用pthread_join回收
        pthread_detach(tid);
        pthread_detach(tid2);
    }
    close(sockfd);

    return 0;
}